#include "stdafx.h"
#include "filesys/temporaryfile.hpp"
#include "filesys/path.hpp"
#include "filesys/process.hpp"
#include "stdlib/exception.hpp"
using namespace JHCPP::stdlib;
#include <event/mutex.hpp>
using JHCPP::event::CMutex;
#include <sstream>

namespace JHCPP
{
	namespace filesys
	{
		//////////////////////////////////////////////////////////////////////////
		//CTempFileCollector
		//////////////////////////////////////////////////////////////////////////
		class CTempFileCollector
		{
		public:
			CTempFileCollector()
			{

			}

			~CTempFileCollector()
			{
				for (std::set<std::string>::iterator it = m_files.begin(); it != m_files.end(); ++it)
				{
					try
					{
						CFile f(*it);
						f.remove(true);
					}
					catch (CException&)
					{
					}
				}
			}

			void registerFile(const std::string& path)
			{
				CMutex::ScopedLock lock(m_mutex);

				CPath p(path);
				m_files.insert(p.absolute().toString());
			}

		private:
			std::set<std::string>	m_files;
			CMutex					m_mutex;
		};

		//////////////////////////////////////////////////////////////////////////
		//CTemporaryFile
		//////////////////////////////////////////////////////////////////////////
		CTemporaryFile::CTemporaryFile() : CFile(tempName()), m_keep(false)
		{
		}

		CTemporaryFile::CTemporaryFile(const std::string& tempDir) : CFile(tempName(tempDir)), m_keep(false)
		{
		}

		CTemporaryFile::~CTemporaryFile()
		{
			if (!m_keep)
			{
				try
				{
					if (exists())
						remove(true);
				}
				catch (CException&)
				{
				}
			}
		}

		void CTemporaryFile::keep()
		{
			m_keep = true;
		}

		void CTemporaryFile::keepUntilExit()
		{
			m_keep = true;
			registerForDeletion(path());
		}

		static CTempFileCollector fc;
		static CMutex mutex;

		void CTemporaryFile::registerForDeletion(const std::string& path)
		{
			fc.registerFile(path);
		}

		std::string CTemporaryFile::tempName(const std::string& tempDir)
		{
			std::ostringstream name;
			static unsigned long count = 0;
			mutex.lock();
			unsigned long n = count++;
			mutex.unlock();
			name << (tempDir.empty() ? CPath::temp() : tempDir);

			name << "tmp" << CProcess::id();

			for (int i = 0; i < 6; ++i)
			{
				name << char('a' + (n % 26));
				n /= 26;
			}
			return name.str();
		}
	}//end of namespace filesys
}//end of namespace JHCPP